package com.gage.print.pdf;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.print.PrintService;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.gage.print.pdf.model.Major;
import com.gage.print.pdf.model.Student;
import com.gage.print.pdf.util.Constant;
import com.gage.print.pdf.util.PDFUtil;
import com.gage.print.pdf.util.Page;
import com.gage.print.pdf.util.PrintUtil;
import com.gage.print.pdf.util.WordTemplate;
import com.gage.print.pdf.vo.PrintMessage;
import com.gage.print.pdf.vo.Result;
import com.google.zxing.WriterException;

@Controller
public class FirstAction {
	@Value("#{propertiesReader['savePath']}")
	private String savePath;
	@Value("#{propertiesReader['uploadFolder']}")
	private String uploadFolder;
	@Value("#{propertiesReader['printFolder']}")
	private String printFolder;
	@Value("#{propertiesReader['coverFolder']}")
	private String coverFolder;

	@RequestMapping("index")
	public ModelAndView index(@RequestParam(defaultValue = "1") int currentPage,
			@RequestParam(required = false) String majorCode) {
		ModelAndView view = new ModelAndView("index");

		Page page = new Page(currentPage);

		List<Major> majorList = Constant.MAJOR_LIST;
		List<Result> resultList = getPage(page, majorCode);

		view.addObject("majorList", majorList);
		checkStatus(resultList);
		view.addObject("resultList", resultList);
		view.addObject("page", page);
		view.addObject("majorCode", majorCode);

		return view;
	}

	@RequestMapping("downloadTemplate")
	public void downloadTemplate(HttpServletResponse response, String[] majorCode) throws IOException, WriterException {
		OutputStream outputStream = response.getOutputStream();

		response.setHeader("Pragma", "no-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setHeader("Expires", "0");
		response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
		response.setCharacterEncoding("utf-8");

		if (majorCode != null) {
			String fileName = null;
			Writer out = null;

			if (majorCode.length > 1) {
				outputStream = new ZipOutputStream(outputStream);
				out = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
				response.setContentType("application zip");
			} else {
				response.setContentType("application msword");
			}

			for (int i = 0; i < majorCode.length; i++) {
				Major major = Constant.MAJOR_MAP.get(majorCode[i]);
				boolean checkMajor = checkMajor(major);

				if (checkMajor) {
					if (majorCode.length == 1) {
						fileName = major.getMajorName() + "[" + major.getMajorCode() + "].doc";

						response.setHeader("Content-disposition",
								"attachment;filename=\"" + new String(fileName.getBytes("gb2312"), "ISO8859_1") + "\"");
						WordTemplate.genrateWordTemplate(outputStream, major.getMajorCode(), major.getMajorName());
					} else {
						if (fileName == null) {
							fileName = "试卷压缩包.zip";
							response.setHeader("Content-disposition", "attachment;filename=\""
									+ new String(fileName.getBytes("gb2312"), "ISO8859_1") + "\"");
						}

						((ZipOutputStream) outputStream).putNextEntry(
								new ZipEntry(major.getMajorName() + "[" + major.getMajorCode() + "].doc"));
						WordTemplate.genrateWordTemplate(outputStream, out, major.getMajorCode(), major.getMajorName());
					}

				}
			}

			if (majorCode.length > 1) {
				out.flush();
				out.close();
			}
			outputStream.flush();
			outputStream.close();
		}
	}

	@RequestMapping("upload")
	@ResponseBody
	public String upload(@RequestParam MultipartFile pdfFile, HttpSession session) {
		if (!Boolean.valueOf(true).equals((Boolean) session.getAttribute("uploading"))) {
			session.setAttribute("uploading", true);

			try {
				List<String> codeList = PDFUtil.decode_PDF_QRCode(560, 30, 660, 130, pdfFile.getBytes());
				if (codeList != null && codeList.size() > 0) {
					Major major = Constant.MAJOR_MAP.get(codeList.get(0));
					if (major != null) {
						if (!(major.getMajorName() + "[" + major.getMajorCode() + "]" + ".pdf")
								.equals(pdfFile.getOriginalFilename())) {
							session.removeAttribute("uploading");
							return "file_name_error";
						}
						StringBuilder saveFilePath = getUploadFolderPath();
						saveFilePath.append(File.separator);
						saveFilePath.append(major.getMajorCode());
						saveFilePath.append(".pdf");

						File file = new File(saveFilePath.toString());

						if (file.exists()) {
							session.setAttribute("coverCode", major.getMajorCode());
							StringBuilder coverFilePath = getCoverFolderPath();
							coverFilePath.append(File.separator);
							coverFilePath.append(major.getMajorCode());
							coverFilePath.append(".pdf");

							File coverFile = new File(coverFilePath.toString());
							if (coverFile.exists()) {
								coverFile.delete();
							}
							if (coverFile.getParentFile() != null && !coverFile.getParentFile().exists()) {
								coverFile.getParentFile().mkdirs();
							}
							OutputStream os = new FileOutputStream(coverFile);
							os.write(pdfFile.getBytes());
							os.close();

							session.removeAttribute("uploading");
							return "exists";
						}

						if (file.getParentFile() != null && !file.getParentFile().exists()) {
							file.getParentFile().mkdirs();
						}

						OutputStream os = new FileOutputStream(file);
						os.write(pdfFile.getBytes());
						os.close();

						session.removeAttribute("uploading");
						return "success";
					} else {
						session.removeAttribute("uploading");
						return "not_found";
					}
				} else {
					session.removeAttribute("uploading");
					return "not_found";
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		session.removeAttribute("uploading");
		return "error";
	}

	@RequestMapping("upload/cover")
	@ResponseBody
	public void cover(HttpSession session) {
		String majorCode = (String) session.getAttribute("coverCode");

		if (majorCode != null) {
			StringBuilder coverFilePath = getCoverFolderPath();
			coverFilePath.append(File.separator);
			coverFilePath.append(majorCode);
			coverFilePath.append(".pdf");

			StringBuilder filePath = getUploadFolderPath();
			filePath.append(File.separator);
			filePath.append(majorCode);
			filePath.append(".pdf");

			File coverFile = new File(coverFilePath.toString());
			File file = new File(filePath.toString());
			if (coverFile.exists()) {
				OutputStream os = null;
				InputStream is = null;
				try {
					byte[] ba = new byte[1024];
					int length = -1;

					is = new FileInputStream(coverFile);
					os = new FileOutputStream(file);

					while ((length = is.read(ba)) != -1) {
						os.write(ba, 0, length);
					}
					is.close();
					os.close();
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					if (os != null)
						try {
							os.close();
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					if (is != null)
						try {
							is.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
				}

				coverFile.delete();
			}

			session.removeAttribute("coverCode");
		}
	}

	@RequestMapping("download")
	public void download(HttpServletResponse response, @RequestParam(required = false) String majorCode) {
		StringBuilder filePath = getUploadFolderPath();
		filePath.append(File.separator);
		filePath.append(majorCode);
		filePath.append(".pdf");
		File file = new File(filePath.toString());
		if (file.exists()) {
			OutputStream os = null;
			InputStream is = null;
			try {
				os = response.getOutputStream();
				is = new FileInputStream(file);

				byte[] ba = new byte[1024];
				int length = -1;
				while ((length = is.read(ba)) != -1) {
					os.write(ba, 0, length);
				}
				os.flush();
				os.close();
				is.close();

			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (os != null)
					try {
						os.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				if (is != null)
					try {
						is.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
			}
		}
	}

	@RequestMapping("print")
	@ResponseBody
	public Map<String, Object> print(HttpSession session, String[] majorCode) throws IOException, WriterException {
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("status", "success");
		for (String code : majorCode) {
			StringBuilder filePath = getUploadFolderPath();
			filePath.append(File.separator);
			filePath.append(code);
			filePath.append(".pdf");
			File file = new File(filePath.toString());
			if (file.exists()) {
				StringBuilder printMajorFolderPath = getPrintFolderPath();
				printMajorFolderPath.append(File.separator);
				printMajorFolderPath.append(code);
				File printMajorFolder = new File(printMajorFolderPath.toString());
				if (printMajorFolder.exists()) {
					printMajorFolder.delete();

					if (!printMajorFolder.isFile()) {
						for (File f : printMajorFolder.listFiles()) {
							if (f.exists())
								f.delete();
						}
					}
				}

				List<Result> resultList = Constant.RESULT_LIST;
				for (Result r : resultList) {
					if (code.equals(r.getMajorCode())) {
						int currentFileIndex = 0;
						for (Student s : r.getStudentList()) {
							StringBuilder printFilePath = getPrintFolderPath();
							printFilePath.append(File.separator);
							printFilePath.append(code);
							printFilePath.append(File.separator);
							printFilePath.append(s.getStudentNo());
							printFilePath.append(".pdf");

							File printFile = new File(printFilePath.toString());
							if (printFile.exists()) {
								printFile.delete();
							}

							if (printFile.getParentFile() != null && !printFile.getParentFile().exists()) {
								printFile.getParentFile().mkdirs();
							}

							PrintMessage printMessage = new PrintMessage();
							printMessage.setMajorCode(r.getMajorCode());
							printMessage.setMajorName(r.getMajorName());
							printMessage.setStudentName(s.getName());
							printMessage.setStudentNo(s.getStudentNo());

							try {
								PDFUtil.dealWithPDF(file, printFile, printMessage, currentFileIndex++);
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
						break;
					}
				}
			} else {
				result.put("status", "not_exists");
				return result;
			}
		}

		PrintService[] allPrintService = PrintUtil.searchAllPrintService();
		List<Map<String, Object>> allPrintServiceList = new ArrayList<Map<String, Object>>();
		for (PrintService ps : allPrintService) {
			Map<String, Object> psMap = new HashMap<String, Object>();

			psMap.put("name", ps.getName());

			Class<?>[] supportedAttributeCategories = ps.getSupportedAttributeCategories();
			for (Class<?> supportAttribute : supportedAttributeCategories) {
				psMap.put(supportAttribute.getSimpleName(), true);
			}

			allPrintServiceList.add(psMap);
		}

		result.put("allPrintService", allPrintServiceList);
		session.setAttribute("printMajorCode", majorCode);
		return result;
	}

	@RequestMapping("startPrint")
	@ResponseBody
	public String startPrint(HttpSession session, @RequestParam(name = "printService") String printServiceName) {
		PrintService printService = PrintUtil.getPrintService(printServiceName);
		if (printService == null) {
			return "not_exists";
		} else {
			String[] majorCode = (String[]) session.getAttribute("printMajorCode");
			if (majorCode == null || majorCode.length == 0) {
				return "session_timeout";
			}

			for (String code : majorCode) {
				StringBuilder printFolderPath = getPrintFolderPath();
				printFolderPath.append(File.separator);
				printFolderPath.append(code);
				File printFolder = new File(printFolderPath.toString());
				if (printFolder != null && printFolder.exists() && printFolder.isDirectory()) {
					File[] listFiles = printFolder.listFiles();
					for (File f : listFiles) {
						PrintUtil.print(f, printService);
					}
				}
			}
		}

		session.removeAttribute("printMajorCode");
		return "success";
	}

	private boolean checkMajor(Major major) {
		return major != null && !StringUtils.isBlank(major.getMajorCode());
	}

	private List<Result> getPage(Page page, String majorCode) {
		List<Result> allResultList = null;
		if (StringUtils.isNotBlank(majorCode) && checkMajor(Constant.MAJOR_MAP.get(majorCode))) {
			allResultList = new ArrayList<Result>();
			for (Result r : Constant.RESULT_LIST) {
				if (majorCode.equals(r.getMajorCode())) {
					allResultList.add(r);
				}
			}
		} else {
			allResultList = Constant.RESULT_LIST;
		}
		page.setTotal(allResultList.size());
		if (page.getCurrent() > page.getPages()) {
			page.setCurrent(page.getPages());
		}
		int startIndex = (page.getCurrent() - 1) * page.getPageSize();
		int endIndex = page.getCurrent() * page.getPageSize();
		if (startIndex > allResultList.size()) {
			startIndex = allResultList.size();
		}
		if (endIndex > allResultList.size()) {
			endIndex = allResultList.size();
		}
		return allResultList.subList(startIndex, endIndex);
	}

	private void checkStatus(List<Result> resultList) {
		StringBuilder filePath = getUploadFolderPath();

		for (Result r : resultList) {
			StringBuilder checkFilePath = new StringBuilder();
			checkFilePath.append(filePath);
			checkFilePath.append(File.separator);
			checkFilePath.append(r.getMajorCode());
			checkFilePath.append(".pdf");
			File file = new File(checkFilePath.toString());
			if (file.exists()) {
				r.setStatus(1);
			}
			else {
				r.setStatus(0);
			}
		}
	}

	private StringBuilder getPrintFolderPath() {
		StringBuilder printFolderPath = new StringBuilder();
		printFolderPath.append(savePath);
		printFolderPath.append(File.separator);
		printFolderPath.append(printFolder);
		return printFolderPath;
	}

	private StringBuilder getUploadFolderPath() {
		StringBuilder printFolderPath = new StringBuilder();
		printFolderPath.append(savePath);
		printFolderPath.append(File.separator);
		printFolderPath.append(uploadFolder);
		return printFolderPath;
	}

	private StringBuilder getCoverFolderPath() {
		StringBuilder printFolderPath = new StringBuilder();
		printFolderPath.append(savePath);
		printFolderPath.append(File.separator);
		printFolderPath.append(coverFolder);
		return printFolderPath;
	}
}
